package com.pb.service.boot.config;

import com.alibaba.fastjson.JSON;
import com.pb.infra.oth.util.*;
import org.apache.poi.openxml4j.util.ZipSecureFile;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * 廖昊源
 * 2021.3.28
 * 自定义参数解析器，用来导入excel文件
 */
@Configuration
public class ImportExcelArgumentResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        return methodParameter.hasParameterAnnotation(ImportExcel.class);
    }

    @Override
    public Map<String,Object> resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
        HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
        MultipartHttpServletRequest multRequest = nativeWebRequest.getNativeRequest(MultipartHttpServletRequest.class);
        StringBuffer sbf1=new StringBuffer();
        String token = request.getHeader("uc-token");
        String corpId = request.getHeader("corpId");
        RedisUtil redisUtil = SpringContextUtil.getBean(RedisUtil.class);
        UserInfo userInfo=(UserInfo) redisUtil.get(token);
        String userId=userInfo.getUserId();
        Map<String, Object> responseMap = new HashMap<String, Object>();
        List<List<Map<String,Object>>> data=new ArrayList<>();
        InputStream input = null;
        if (request==null || multRequest==null){
            throw new Exception("请求异常，请与管理员联系");
        }
        try {
            MultipartFile excelFile = multRequest.getFile("excel-file");
            input = excelFile.getInputStream();
            byte[] bytes = new byte[4];
            InputStream inputStream = null;
            try {
                inputStream = excelFile.getInputStream();
                inputStream.read(bytes);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                }
            }
            String result = FileTypeUtils.bytesToHexString(bytes);
            if (!FileTypeEnum.XLSX.getMagicNumberCode().equals(result)) {
                responseMap.put("msg", "请上传 《.xlsx》 类型的文件");
                responseMap.put("code", -1);
                return responseMap;
            }
            ZipSecureFile.setMinInflateRatio(-1.0d);
            XSSFWorkbook workbook = new XSSFWorkbook(input);
            int sheetNumber = workbook.getNumberOfSheets();
            int sheetColNum;
            int RowNum;
            String sheetName;
            String[][] dataNames = new String[][]{};
            String[][] emptyJudges = new String[][]{};
            String[][] regulars = new String[][]{};
            String[][] dataTypes = new String[][]{};
            String[][] PrimaryKey = new String[][]{};
            Map<String, String[]> requestMap = request.getParameterMap();
            for (Object o : requestMap.entrySet()) {
                Map.Entry me = (Map.Entry) o;
                String keys = (String) me.getKey();
                String[] values = (String[]) me.getValue();
                for (int i = 0; i < values.length; i++) {
                    switch (keys) {
                        case "dataName":
                            dataNames = JSON.parseObject(values[i], String[][].class);
                            break;
                        case "emptyJudge":
                            emptyJudges = JSON.parseObject(values[i], String[][].class);
                            break;
                        case "regular":
                            regulars = JSON.parseObject(values[i], String[][].class);
                            break;
                        case "dataType":
                            dataTypes = JSON.parseObject(values[i], String[][].class);
                            break;
                        case "PrimaryKey":
                            PrimaryKey = JSON.parseObject(values[i], String[][].class);
                            break;
                    }
                }
            }
            // String appId=request.getParameter("appId");
            DataFormatter formatter = new DataFormatter();
            boolean dataFlag = true;
            for (int i = 0; i < sheetNumber; i++) {
                StringBuffer sbf = new StringBuffer();
                boolean sheetflag = true;
                assert dataNames != null;
                String[] dataName = dataNames[i];
                String[] emptyJudge = emptyJudges[i];
                String[] dataType = dataTypes[i];
                String[] regular = regulars[i];
                XSSFSheet sheet = workbook.getSheetAt(i);
                sheetName = sheet.getSheetName();
                sheetColNum = sheet.getRow(0).getPhysicalNumberOfCells();            //导入列数
                RowNum = sheet.getLastRowNum();
                List<Map<String, Object>> rowData = new ArrayList<Map<String, Object>>();
                List<String> key = new ArrayList<>();
                if (sbf.toString().length() == 0) {
                    sbf.append("<br/><span style='color:blue;font-weight:bold;'>《" + sheetName + "》:</span>");
                }
                for (int j = 1; j <= RowNum; j++) {
                    StringBuffer rowBuffer = new StringBuffer();
                    //遍历每一行（从工作簿第1行开始读取）
                    XSSFRow row = sheet.getRow(j);
                    Map<String, Object> map = new HashMap<>();
                    map.put("userId", userId);
                    map.put("corpId", corpId);
                    boolean rowFlag = true;
                    ExcelUtil.concatString(row, sheetColNum, formatter);
                    if (row != null && !ExcelUtil.concatString(row, sheetColNum, formatter)) {
                        if (rowBuffer.toString().length() == 0) {
                            rowBuffer.append("<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第<b>" + (j + 1) + "</b>行数据:");
                        }
                        //主键校验
                        if (PrimaryKey != null && PrimaryKey.length > 0) {
                            StringBuffer buffer = new StringBuffer();
                            StringBuffer name = new StringBuffer();
                            for (int r = 0; r < PrimaryKey[i].length; r++) {
                                if ("key".equals(PrimaryKey[i][r])) {
                                    String cellValue = ExcelUtil.getStringCellValues(formatter, row.getCell(r));
                                    String colName = sheet.getRow(0).getCell(r).getStringCellValue();
                                    buffer.append(cellValue);
                                    name.append(colName);
                                    if (r != PrimaryKey[i].length - 1) {
                                        name.append(",");
                                    }
                                }
                            }
                            if (key.contains(buffer.toString())) {
                                rowBuffer.append("<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" + name.toString() + "字段数据重复");
                                rowFlag = false;
                            } else {
                                key.add(buffer.toString());
                            }
                        }
                        for (int k = 0; k < sheetColNum; k++) {
                            String colName = sheet.getRow(0).getCell(k).getStringCellValue();
                            boolean flag = true;
                            //遍历每一个单元格
                            String cellValue = ExcelUtil.getCellValue(row.getCell(k));// ExcelUtil.getStringCellValues(formatter,row.getCell(k));
                            if ("NOTNULL".equals(emptyJudge[k])) {
                                if (cellValue == null || "".equals(cellValue)) {
                                    rowBuffer.append("<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<" + colName + ">不能为空");
                                    flag = false;
                                }
                            }
                            if ("NUMBER".equals(dataType[k])) {
                                Pattern pattern = Pattern.compile("^\\d+(\\.\\d+)?$");
                                if (!pattern.matcher(cellValue).matches()) {
                                    rowBuffer.append("<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<" + colName + ">数据类型错误");
                                    flag = false;
                                }
                            }
                            if (regular.length > 0) {
                                if (regular[k] != null && !"".equals(regular[k]) && !" ".equals(regular[k])) {
                                    String[] split = regular[k].split("-");
                                    boolean status = false;
                                    for (int l = 0; l < split.length; l++) {
                                        if (cellValue.replace("-", "").matches("\\d+.\\d+")) {
                                            double value = Double.parseDouble(cellValue);
                                            double v = Double.parseDouble(split[l]);
                                            if (value == v) {
                                                status = true;
                                            }
                                        } else {
                                            if (cellValue.equals(split[l])) {
                                                status = true;
                                            }
                                        }
                                        if (l == split.length - 1 && !status) {
                                            rowBuffer.append("<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<" + colName + ">输入数据错误");
                                            flag = false;
                                        }
                                    }
                                }
                            }
                            if (flag) {
                                map.put(dataName[k], cellValue);
                            } else {
                                responseMap.put("code", -1);
                                rowFlag = false;
                            }
                        }
                    } else {
                        break;
                    }
                    rowData.add(map);
                    if (!rowFlag) {
                        sbf.append(rowBuffer.toString());
                        sheetflag = false;
                    }
                }
                if (sheetflag) {
                } else {
                    dataFlag = false;
                    sbf1.append(sbf.toString());
                }
                data.add(rowData);
            }
            if (dataFlag) {
                responseMap.put("msg", "");
                responseMap.put("data", data);
                // responseMap.put("appId", appId);
                responseMap.put("code", 1);
            } else {
                responseMap.put("msg", sbf1.toString());
                responseMap.put("data", data);
                responseMap.put("code", -1);
            }
        } catch (Exception e) {
            responseMap.put("code", -1);
            responseMap.put("msg", "导入失败");
            e.printStackTrace();
        } finally {
            try {
                if (input != null) {
                    input.close();
                }
            } catch (IOException e) {
                responseMap.put("code", -1);
                responseMap.put("msg", "导入失败");
                e.printStackTrace();
            }
        }
        return responseMap;
    }
}
